package tetris.game.model;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Vector;

public enum BlockFactory {
	INSTANCE;
	
	private static Random random = new Random(System.currentTimeMillis());
	
	private static BlockType[] blockTypeArray = BlockType.values();
	
	/**
	 * A mapping of each BlockType to a certain Color.
	 */
	private static Map<BlockType, Color> colorMap = new HashMap<BlockType, Color> ();
	
	// create the mapping of BlockTypes to Colors randomly on initialization
	static {
		Color[] colorArray = Color.values();
		// create a list of all BlockTypes
		List<BlockType> blockTypes = new Vector<BlockType> ();
		for(int i = 0; i< blockTypeArray.length; i++) 
			blockTypes.add(blockTypeArray[i]);
		// do the same for the colors
		List<Color> colors = new Vector<Color> ();
		// ensure that the background color BLACK (last entry of Color enum) is left out
		for(int i = 0; i< colorArray.length-1; i++) {
			colors.add(colorArray[i]);
		}
		
		// finally create the mapping
		int freeColors = colors.size(); // amount of still available colors
		int selection;					// number of the currently selected color
		Color color;					// the chosen color
		for(BlockType type : blockTypes) {
			// choose a color
			selection = random.nextInt(freeColors);
			freeColors--;
			color = colors.remove(selection);
			// add the combination to the mapping
			colorMap.put(type, color);
		}
	}
	
	/**
	 * Generates a new random Tetris Block.
	 * @return the new Block object
	 */
	public Block generateRandomBlock() {
		// choose a random number
		int selection = random.nextInt(28);
		// calculate BlockType and rotation based on this
		int typeNr = selection / 4;
		int orientation = (selection % 4) * 90;
		// return the matching Block object
		switch(typeNr) {
		case 0:
			return new Block(BlockType.L, colorMap.get(BlockType.L), orientation);
		case 1:
			return new Block(BlockType.J, colorMap.get(BlockType.J), orientation);
		case 2:
			return new Block(BlockType.T, colorMap.get(BlockType.T), orientation);
		case 3:
			return new Block(BlockType.Z, colorMap.get(BlockType.Z), orientation);
		case 4:
			return new Block(BlockType.S, colorMap.get(BlockType.S), orientation);
		case 5:
			return new Block(BlockType.I, colorMap.get(BlockType.I), orientation);
		case 6:
			return new Block(BlockType.O, colorMap.get(BlockType.O), orientation);
		// should never happen
		default:
			throw new IllegalStateException("BlockType number is invalid: " + typeNr);
		}
		// TODO: clean up
		// TODO: blockTypeArray can most likely be removed then
		// choose a random block type
	//	BlockType blockType = blockTypeArray[random.nextInt(7)];
		// generate the new Block with matching color
	//	Block block = new Block(blockType, colorMap.get(blockType));
	//	return block;
	}
	
	/**
	 * Used to set the seed (long) of the random generator for Multiplayer games,
	 * to grant that both players get the same series of Blocks.
	 * @param seed the seed value to be set
	 */
	public void setSeed(long seed) {
		random = new Random(seed);
	}
}
